Skip to content

new blog on upcoming changes for weighted graph models#1259

Open
tylernix wants to merge 6 commits into
mainfrom
blog/check-v2-upcoming-changes
Open

new blog on upcoming changes for weighted graph models#1259
tylernix wants to merge 6 commits into
mainfrom
blog/check-v2-upcoming-changes

Conversation

@tylernix

@tylernix tylernix commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds blog post explaining OpenFGA's transition to a weighted graph-based resolution algorithm for Check
  • Covers the 5 incompatible patterns: missing TTU relations, tuple cycles with AND/BUT NOT, userset/wildcard checks against exclusion, userset alias inference, and self-referential userset checks
  • Includes migration guidance and examples for model fixes for each pattern

Summary by CodeRabbit

Release Notes

  • Documentation
    • Published blog post detailing upcoming changes to Check resolution algorithm, including new model validation errors, behavioral modifications, and a validation checklist to help users prepare for the transition.

Review Change Stack

Copilot AI review requested due to automatic review settings May 14, 2026 03:50
@tylernix tylernix requested review from a team as code owners May 14, 2026 03:50
@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dfc256e6-bad8-43fa-82b9-e46f2eda3831

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

A new blog post announces OpenFGA's rollout of weighted graph-based Check resolution. It contrasts the legacy recursive approach with build-time graph construction, details breaking changes in model validation and Check behavior, and provides migration guidance including error scenarios, validation checklists, timeline, and community resources.

Changes

Weighted Graph Migration Announcement

Layer / File(s) Summary
Post metadata and announcement scope
blog/weighted-graph-upcoming-changes.md (front matter and intro)
Blog front matter and introduction establish the weighted graph rollout topic, explain that ListObjects already uses weighted graph while Check is next, set expectations about temporary fallback behavior for incompatible models, and emphasize the need to migrate before fallback removal.
Technical motivation and architecture context
blog/weighted-graph-upcoming-changes.md (Why section)
Contrasts legacy request-time recursion (depth limits, error-handling constraints) against build-time graph construction and weighted traversal, highlighting determinism and improved load management.
Breaking changes and error scenarios
blog/weighted-graph-upcoming-changes.md (What's Changing, Check Request Errors, Check Resolution Changes sections)
Documents two model build errors (missing referenced relations for relation from parent, tuple cycles from and/but not), details Check request errors for exclusion-based relations with userset/wildcard inputs and workarounds, and explains Check resolution changes (strict userset relation name matching, self-referential usersets returning FALSE instead of TRUE without tuples).
Migration checklist, timeline, and support
blog/weighted-graph-upcoming-changes.md (How to Check, Timeline, Get Help sections)
Provides a practical checklist for validating model impact (model validation, auditing check patterns, using .fga.yaml tests), describes rollout stages with CLI validation command and final enforcement date, and links to community resources for migration help.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a blog post about upcoming changes for weighted graph models, which matches the changeset perfectly.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch blog/check-v2-upcoming-changes

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@blog/weighted-graph-upcoming-changes.md`:
- Line 14: Change the wording for clarity in the file's intro and model-error
sentence: replace the phrase “update algorithm” with “updated algorithm” in the
sentence that begins “OpenFGA is continuing to roll out a **weighted graph-based
resolution algorithm**…” and change the verb usage “models fallback” (around
line referencing model errors) to “models fall back” or “models revert to the
legacy algorithm” so the phrasing reads naturally and consistently.
- Around line 143-146: The fenced code blocks containing example calls like
check("document:report", "viewer", "document:contract#owner"),
check("document:readme", "viewer", "user:*"), check("document:report", "viewer",
"user:alice"), the blocks with write(document:source#allowed, viewer,
document:target), and the other examples are missing language identifiers;
update each triple-backtick fence to include a language (e.g., ```text) so lint
rule MD040 is satisfied and syntax highlighting works, ensuring you modify every
block that wraps calls to check(...) and write(...) as noted in the review.
- Line 234: Update the heading text "How to Check If You're Model Is Affected"
to use the possessive form by replacing "You're" with "Your" so it reads "How to
Check If Your Model Is Affected"; locate and edit the heading string in the
markdown (the line containing that exact heading) to correct the typo.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f9957dc6-a926-445e-974f-d4af69cc4a72

📥 Commits

Reviewing files that changed from the base of the PR and between 2108fb7 and a4782f8.

📒 Files selected for processing (1)
  • blog/weighted-graph-upcoming-changes.md

Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://openfga.github.io/openfga.dev/pr-preview/pr-1259/

Built to branch gh-pages at 2026-05-14 04:37 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new blog post describing OpenFGA’s upcoming weighted graph-based Check resolution changes, the incompatible modeling/check patterns, and migration guidance.

Changes:

  • Introduces a new announcement/migration blog post.
  • Documents five affected patterns with examples and suggested fixes.
  • Adds timeline and support links for users preparing migrations.
Comments suppressed due to low confidence (9)

blog/weighted-graph-upcoming-changes.md:69

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:80

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:97

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:106

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:117

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:135

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:150

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:184

  • OpenFGA model snippets elsewhere use dsl.openfga fences for site syntax highlighting (for example, blog/conditional-tuples-announcement.md:23 and docs/content/getting-started/perform-list-users.mdx:100). Using plain dsl here deviates from that convention and may lose OpenFGA-specific highlighting.
```dsl

blog/weighted-graph-upcoming-changes.md:256

  • This sentence is missing the article before "weighted graph algorithm"; it should read "the weighted graph algorithm".

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment thread blog/weighted-graph-upcoming-changes.md
Comment thread blog/weighted-graph-upcoming-changes.md
Comment thread blog/weighted-graph-upcoming-changes.md

```
write(document:source#allowed, viewer, document:target) # Already stored
write(document:source#reader, viewer, document:target) # Store explicitly

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot is right about this. The issue is that you can't actually define a tuple for the reader relation since it's not in the model definition. So we're no longer supporting check resolution calls against aliases for usersets.

Suggested change
write(document:source#reader, viewer, document:target) # Store explicitly

Comment thread blog/weighted-graph-upcoming-changes.md Outdated
Comment on lines +115 to +117
**Fix:** Split into a "base" relation (allows recursion) and an "allowed" relation (applies the access gate):

```dsl
@Vic-Dev Vic-Dev requested a review from aaguiarz June 1, 2026 20:21
define viewer: member from parent # but folder has no member, only viewer!
```

**Why this fails:** Access checks through `folder` as `parent` silently return `false` — users never get access even if they should.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little inaccurate. Why it fails is because the weighted graph won't build a graph where all the nodes are not reachable, not because of a false returned during a check.

Suggested change
**Why this fails:** Access checks through `folder` as `parent` silently return `false` — users never get access even if they should.
**Why this fails:** The weighted graph cannot build a graph with unreachable nodes. Since `member` does not exist on `folder`, when the `document.viewer` part of the graph attempts to reach all the `member` relations in `parent`, it fails and does not build.

title: "OpenFGA's Move to Weighted Graph Resolution: What's Changing"
description: "OpenFGA is transitioning to a weighted graph-based resolution algorithm. Learn what's changing, why, and how to migrate your models."
slug: weighted-graph-upcoming-changes
date: 2026-05-14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update this

Suggested change
date: 2026-05-14
date: 2026-06-17

```

> **Migration impact:** Your existing `member` and `blocked` tuples stay exactly as they are — no tuple writes or deletes needed. The only change is in how your application calls Check: replace `check(user, "member", object)` with `check(user, "allowed_member", object)`. The new `allowed_member` relation reads from the same underlying data, just with the exclusion gate applied at the right level.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be too in-depth for this article and better suited to a migration guide, but I just want to capture that some users might want to be able to express hierarchical blocked group membership. How can they do this if we no longer allow the above model? By moving the hierarchy into a TTU relation. Here is an example:

type group
  relations
    define blocked: [user, group#member]
    define blocked_in_hierarchy: blocked or blocked_in_hierarchy from hierarchy_edge
    define hierarchy_edge: [group]
    define member: [user, group#member]
    define allowed_member: member but not blocked_in_hierarchy

However, this would require tuple migration since any pre-existing (group:X#member, member, group:Y) relations would need to be rewritten as (group:X, hierarchy_edge, group:Y), as well as changing their check calls from member to allowed_member. This gets a little complicated to explain, however, and might even require being in its own advanced modelling guide.

relations
define owner: [user]
define member: [user]
define viewer: [document#owner] but not member

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a mistake here, you need to add user in order for the example to work. Eg,

Suggested change
define viewer: [document#owner] but not member
define viewer: [user, document#owner] but not member

check("user:alice", "viewer", "document:report") # ✓ — userset exclusion applied correctly per user
check("user:alice", "viewer", "document:readme") # ✓ — wildcard exclusion applied correctly per user
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This might be better suited to a migration guide, but we could also suggest that users leverage ListUsers here. Eg,

If you need to enumerate who actually has access, use ListUsers:


listUsers("document:report", "viewer") → [user:alice, user:bob]
ListUsers handles both userset and wildcard sources correctly, returning the concrete set of allowed users (with exclusions applied). Note that for wildcard-based relations, this set may be very large, therefore if your original intent was a yes/no "is this fully public?" question, consider modelling publicness as a separate exclusion-free relation rather than reasoning about the full user set.


> **Migration impact:**
> 1. First, check whether your model has any relations that accept a group reference as a value — look for type lists that include `type:object#relation` (e.g., `define viewer: [user, document#allowed]`). If none of your relations accept group references, this change does not affect you.
> 2. If they do exist in your model, audit your check calls for any that pass a group reference as the user. Verify that the relation name in the check matches the relation name used when the tuple was written. If your application relied on alias inference — checking with `#reader` when `#allowed` was stored — update those calls to use the stored relation name, or write additional tuples to explicitly cover the names you check with.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> 2. If they do exist in your model, audit your check calls for any that pass a group reference as the user. Verify that the relation name in the check matches the relation name used when the tuple was written. If your application relied on alias inference — checking with `#reader` when `#allowed` was stored — update those calls to use the stored relation name, or write additional tuples to explicitly cover the names you check with.
> 2. If they do exist in your model, audit your check calls for any that pass a group reference as the user. Verify that the relation name in the check matches the relation name used in the model relation. If your application relied on alias inference — checking with `#reader` when `#allowed` was stored — update those calls to use the stored relation name.


#### 5. Self-Referential Usersets

**What was broken:** Previously, asking "do the viewers of document A have access to document A?" like `check("document:A#viewer", "viewer", "document:A")`, the legacy algorithm always evaluated `TRUE`, just because the relation existed in the model, not because an actual tuple granted that access.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**What was broken:** Previously, asking "do the viewers of document A have access to document A?" like `check("document:A#viewer", "viewer", "document:A")`, the legacy algorithm always evaluated `TRUE`, just because the relation existed in the model, not because an actual tuple granted that access.
**What was broken:** Previously, asking "do the viewers of document A have access to document A?" like `check("document:A#viewer", "viewer", "document:A")`, the legacy algorithm always evaluated `TRUE`, just because the relation existed in the model and the queried user id and object id matched, not because an actual tuple granted that access.


**Next**:
- Check transitions to the weighted graph algorithm as default, also with a fallback.
- Provide a CLI command `fga model validate` to test if your model contains any issues and needs a migration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have this yet, is the intention to communicate that we will have it? Should be more clear:

Suggested change
- Provide a CLI command `fga model validate` to test if your model contains any issues and needs a migration.
- A CLI command `fga model validate` to test if your model contains any issues and needs a migration will be coming soon.

- ListObjects runs on the weighted graph algorithm, with a fallback to the legacy algorithm for incompatible models.

**Next**:
- Check transitions to the weighted graph algorithm as default, also with a fallback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Check transitions to the weighted graph algorithm as default, also with a fallback.
- Check runs on the weighted graph algorithm as default, also with a fallback.

**Next**:
- Check transitions to the weighted graph algorithm as default, also with a fallback.
- Provide a CLI command `fga model validate` to test if your model contains any issues and needs a migration.
- Date announced for final deadline to migrate models before new versions of OpenFGA will only support weighted graph algorithm.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Date announced for final deadline to migrate models before new versions of OpenFGA will only support weighted graph algorithm.
- We will be announcing a final deadline for migrating incompatible models, after which new OpenFGA versions will only support the weighted graph algorithm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants